#ifndef __REG_H__
#define __REG_H__

#include "common.h"
//#include "../../../lib-common/x86-inc/cpu.h"// CR0、CR3

enum { R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI };
enum { R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI };
enum { R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH };

enum { R_ES, R_CS, R_SS, R_DS, R_FS, R_GS}; //段寄存器
/* TODO: Re-organize the `CPU_state' structure to match the register
 * encoding scheme in i386 instruction format. For example, if we
 * access cpu.gpr[3]._16, we will get the `bx' register; if we access
 * cpu.gpr[1]._8[1], we will get the 'ch' register. Hint: Use `union'.
 * For more details about the register encoding scheme, see i386 manual.
 */

typedef struct {
	uint32_t base;  //全局描述符表的基地址
	uint16_t limit; //全局描述符表的大小
}GDTR;

typedef union {
	uint32_t val;
	struct {
		uint32_t pe 		   :1;  //实模式和保护模式的转换的开关，PE=1时为保护模式
		uint32_t mp 		   :1;
		uint32_t em 		   :1;
		uint32_t ts 		   :1;
		uint32_t et 		   :1;
		uint32_t undefined     :26;  //保留位
		uint32_t pg 		   :1;   //是否开启分页
	};	
}CR0;

typedef union {
	uint32_t val;
	struct {
		uint32_t reserve :12;
		uint32_t pdbr    :20;//页目录基地址
	};	
}CR3;

typedef struct{
	//可见部分：
	union{//段选择符
		struct {
			uint32_t rpl   :2;  // 请求特权级 (RPL)，2位
			uint32_t ti    :1;  // 表示选择器是系统段还是用户段 (TI)，1位
			uint32_t index :13; // 索引(INDEX)，13位
		};
		uint16_t selector;
	};
	
	//不可见部分/缓存部分：(在sreg_load函数中加载)
	uint16_t attribute;
	uint32_t limit;
	uint32_t base;
}Segment_Reg;

typedef struct{
	union{
		struct{
			uint16_t limit1;//Limit的0-15位
			uint16_t base1;//Base的0-15位
		};
		uint32_t part1;
	};
	union{
		struct{
			uint32_t base2      :8;//Base的16-23位
			uint32_t a  		:1;
			uint32_t type		:3;
			uint32_t s			:1;
			uint32_t dpl    	:2;
			uint32_t p 			:1;//表示段描述符是否有效
			uint32_t limit2 	:4;//Limit的16-19位
			uint32_t avl    	:1;
			uint32_t        	:1;
			uint32_t x			:1;
			uint32_t g		    :1;//决定limit的高12位或低12位
			uint32_t base3   	:8;//Base的24-31位
			//如果G=0，则段长度Limit范围可从1B～1MB，单位是1B
			//如果G=1，则段长度Limit范围可从4KB～4GB，单位是4KB
		};
		uint32_t part2;
	};
}Sreg_Descriptor;//段描述符
//这里分成part1，part2是因为读写操作每次最多32位，对于64位的段描述符只能分两次来读

typedef struct {
	union {
		struct {
			uint32_t p 		:1; //该页是否有效.
			uint32_t rw		:1;
			uint32_t us		:1;
			uint32_t 		:2;
			uint32_t a		:1;
			uint32_t d 		:1;
			uint32_t 		:2;
			uint32_t avail	:3;
			uint32_t addr 	:20;
		};
		uint32_t val;
	};
}PTE;//页表条目

uint8_t current_sreg;//当前的段寄存器
void sreg_load(uint8_t sreg_id);//用于加载段寄存不可见部分
Sreg_Descriptor *sreg_desc;//储存当前使用的段描述符

typedef struct {
	//通用寄存器
	union{//gpr与8个寄存器共用一块内存
		union{  //联合体，互相覆盖
			uint32_t _32;
			uint16_t _16;
			uint8_t _8[2];
     	} gpr[8];
		struct{  //结构体，不覆盖
			uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
		};
	};
     /* Do NOT change the order of the GPRs' definitions. */
    //eip
	swaddr_t eip;
	//eflags
    union {
		struct {
			uint32_t CF		:1;
			uint32_t pad0	:1;
			uint32_t PF		:1;
			uint32_t pad1	:1;
			uint32_t AF		:1;
			uint32_t pad2	:1;
			uint32_t ZF		:1;
			uint32_t SF		:1;
			uint32_t TF		:1;
			uint32_t IF		:1;
			uint32_t DF		:1;
			uint32_t OF		:1;
			uint32_t IOPL	:2;
			uint32_t NT		:1;
			uint32_t pad3	:1;
			uint16_t pad4;
		};
		uint32_t val;
	} eflags;

	/* Do NOT change the order of the GPRs' definitions. */
	//GDTR
	GDTR gdtr;
	//CR0
	CR0 cr0;
	//segment registers
	union{
		struct{
			Segment_Reg sreg[6];
		};
		struct {
			//注意和前面枚举中顺序一致，因为枚举值作为段寄存器编号和索引
			Segment_Reg es, cs, ss, ds, fs, gs;
		};
	};
	//CR3
	CR3 cr3;

} CPU_state;




extern CPU_state cpu;

static inline int check_reg_index(int index) {
	assert(index >= 0 && index < 8);
	return index;
}

#define reg_l(index) (cpu.gpr[check_reg_index(index)]._32)
#define reg_w(index) (cpu.gpr[check_reg_index(index)]._16)
#define reg_b(index) (cpu.gpr[check_reg_index(index) & 0x3]._8[index >> 2])

extern const char* regsl[];
extern const char* regsw[];
extern const char* regsb[];

#endif
